package com.horizon.cloud.distribute.zookeeper;

import com.horizon.cloud.standard.context.SpringContextUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

@Slf4j
@Data
public class  CuratorZKClient  {
    CuratorFramework client = null;
    private static CuratorZKClient singleton = null;

    //zk集群默认地址
    private static final String ZK_ADDRESS = "127.0.0.1:2181";

    //使用配置方式创建zk时的地址即用@ConditionalOnProperty
    private String zkAddress;

    public CuratorZKClient(String zkAddress) {
        this.zkAddress = zkAddress;

        //构造时，使用独立的线程去初始化，可以让bean加载更快
        init();
    }
/* bean模式和私有静态内部类-静态变量的方法，取其一；由于私有静态内部类-静态变量方法有缺陷，
这次用bean方式
    //内部类初始化对象
    private static class SingletonInstanceHandler{
        static CuratorZKClient singletonInstance = new CuratorZKClient();
    }

    //获取单例的curatorZKClient对象
    public static CuratorZKClient getSingletonInstance(){
        CuratorZKClient singletonInstance = SingletonInstanceHandler.singletonInstance;
        //初始化客户端，可能会被多个线程初始化多次，但是实例只有一个
        singletonInstance.init();
        return singletonInstance;
    }*/

    public static CuratorZKClient getSingletonInstance() {
        if (null == null) {
            singleton = (CuratorZKClient)SpringContextUtil.getBean("zKClient");
        }
        return singleton;
    }

    public void init() {
        if (null != client) {
            return;
        }
        //另起一个线程去初始化client，让bean加载更快
        new Thread(()->{
            //创建客户端
            client = CuratorZKClientFactory.createSimple(ZK_ADDRESS);
            //启动客户端实例，链接服务器
            client.start();
        }).start();
    }

    public void destroy() {
        CloseableUtils.closeQuietly(client);
    }

    /**
     * 创建节点
     */
    public void createPersistentNode(String zkPath, String data) {

        try {
            //创建一个zkNode节点
            //节点的数据为payload
            byte[] payload = "to set content".getBytes("UTF-8");
            if (data != null) {
                payload =data.getBytes("UTF-8");
            }
            client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
                    .forPath(zkPath,payload);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除节点
     */
    public void deleteNode(String zkPath) {
        try {
            if (!isNodeExist(zkPath)) {
                return;
            }
            client.delete().forPath(zkPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 检查节点
     */
    public boolean isNodeExist(String zkPath) {
        try {
            Stat stat = client.checkExists().forPath(zkPath);
            if (null == stat) {
                log.info("节点不存在");
                return false;
            }else {
                log.info("节点存在stat is:", stat.toString());
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 临时顺序节点
     */
    public String createEphemeralSeqNode(String zkPath) {
        try {
            //创建一个znode节点
            String path = client.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    .forPath(zkPath);

            return path;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
